package org.claros.intouch.contacts.controllers;

import java.util.List;
import java.util.Locale;

import javax.mail.internet.InternetAddress;

import org.claros.commons.auth.models.AuthProfile;
import org.claros.commons.exception.NoPermissionException;
import org.claros.intouch.common.utility.Constants;
import org.claros.intouch.common.utility.Utility;
import org.claros.intouch.contacts.models.Contact;
import org.claros.intouch.preferences.controllers.UserPrefsController;

import com.jenkov.mrpersister.impl.mapping.AutoGeneratedColumnsMapper;
import com.jenkov.mrpersister.itf.IGenericDao;
import com.jenkov.mrpersister.itf.mapping.IObjectMappingKey;
import com.jenkov.mrpersister.util.JdbcUtil;

/**
 * @author Umut Gokbayrak
 */
public class ContactsController {
	
	/**
	 * 
	 * @param auth
	 * @param prefix
	 * @return
	 * @throws Exception
	 */
	public static List getContactsByNamePrefix(AuthProfile auth, String prefix) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		try {
			dao = Utility.getDbConnection();
			String username = auth.getUsername();
			
			String displayType = UserPrefsController.getUserSetting(auth, "displayType");
			String sql = null;
			if (displayType == null) {
				displayType = Constants.DISPLAY_TYPE_NAME_FIRST;
			}
			
			if (prefix.equals("ALL")) {
				prefix = "";
			}
			if (displayType == null || displayType.equals(Constants.DISPLAY_TYPE_NAME_FIRST)) {
				sql = "SELECT * FROM CONTACTS WHERE USERNAME=? AND UPPER(FIRST_NAME) LIKE '" + prefix + "%'";
			} else if (displayType.equals(Constants.DISPLAY_TYPE_SURNAME_FIRST)) {
				sql = "SELECT * FROM CONTACTS WHERE USERNAME=? AND UPPER(LAST_NAME) LIKE '" + prefix + "%'";
			}
			contacts = dao.readList(Contact.class, sql, new Object[] {username});
			contacts = org.claros.intouch.contacts.utility.Utility.sortContacts(contacts, displayType.equals(Constants.DISPLAY_TYPE_NAME_FIRST));
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return contacts;
	}

	/**
	 * @param auth
	 * @param contact
	 */
	public static void saveContact(AuthProfile auth, Contact contact) throws Exception {
		IGenericDao dao = null;
		try {
			dao = Utility.getDbConnection();
			
			Long id = contact.getId();
			if (id == null) {
				// it is an insert
				IObjectMappingKey myObj = Constants.persistMan.getObjectMappingFactory().createInstance(Contact.class, new AutoGeneratedColumnsMapper(true));
				dao.insert(myObj, contact);
			} else {
				// it is an update
				Contact tmp = getContactById(auth, contact.getId());
				if (!tmp.getUsername().equals(auth.getUsername())) {
					throw new NoPermissionException();
				}
				dao.update(contact);
			}
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
	}

	/**
	 * 
	 * @param auth
	 * @param id
	 * @return
	 * @throws Exception
	 */
	public static Contact getContactById(AuthProfile auth, Long id) throws Exception {
		IGenericDao dao = null;
		Contact result = null;
		try {
			dao = Utility.getDbConnection();
			result = (Contact)dao.readByPrimaryKey(Contact.class, id);

			if (!result.getUsername().equals(auth.getUsername())) {
				throw new NoPermissionException();
			}
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return result;
	}

	/**
	 * 
	 * @param auth
	 * @param id
	 * @throws Exception
	 */
	public static void deleteContact(AuthProfile auth, Long id) throws Exception {
		Contact tmp = getContactById(auth, id);
		if (!tmp.getUsername().equals(auth.getUsername())) {
			throw new NoPermissionException();
		}

		IGenericDao dao = null;
		try {
			dao = Utility.getDbConnection();
			dao.deleteByPrimaryKey(Contact.class, id);
		} catch (Exception e) {
			// do nothing sier
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
	}

	/**
	 * @param auth
	 * @param address
	 * @param company
	 * @param email
	 * @param name
	 * @param phone
	 * @return
	 */
	public static List searchContacts(AuthProfile auth, String address, String company, String email, String name, String phone) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		try {
			dao = Utility.getDbConnection();
			String username = auth.getUsername();
			
			String sql = "SELECT * FROM CONTACTS WHERE USERNAME=? ";
			
			// address conditions
			if (address != null && address.trim().length() != 0) {
				sql += "AND (" +					   "	upper(HOME_ADDRESS) like '%" + address + "%' or " +					   "	upper(HOME_CITY) like '%" + address + "%' or " +					   "	upper(HOME_PROVINCE) like '%" + address + "%' or " +					   "	HOME_ZIP like '%" + address + "%' or " +					   "	upper(HOME_COUNTRY) like '%" + address + "%' or " +					   "	upper(WORK_ADDRESS) like '%" + address + "%' or " +					   "	upper(WORK_CITY) like '%" + address + "%' or " +					   "	upper(WORK_PROVINCE) like '%" + address + "%' or " +
					   "	WORK_ZIP like '%" + address + "%' or " +
					   "	upper(WORK_COUNTRY) like '%" + address + "%') ";
			}
			
			// company criteria
			if (company != null && company.trim().length() != 0) {
				sql += "or upper(WORK_COMPANY) like '%" + company + "%' ";
			}

			// search emails
			if (email != null && email.trim().length() != 0) {
				sql += "or (" +					   "	upper(EMAIL_PRIMARY) like '%" + email + "%' or " +					   "	upper(EMAIL_ALTERNATE) like '%" + email + "%') ";
			}

			// search names
			if (name != null && name.trim().length() != 0) {
				sql += "or (" +
					   "	upper(FIRST_NAME) like '%" + name + "%' or " +
					   "	upper(MIDDLE_NAME) like '%" + name + "%' or " +					   "	upper(LAST_NAME) like '%" + name + "%') ";
			}
			
			// search phones
			if (phone != null && phone.trim().length() != 0) {
				sql += "or (" +
					   "	GSM_NO_PRIMARY like '%" + phone + "%' or " +
					   "	GSM_NO_ALTERNATE like '%" + phone + "%' or " +
					   "	HOME_PHONE like '%" + phone + "%' or " +
					   "	WORK_PHONE like '%" + phone + "%') ";
			}

			contacts = dao.readList(Contact.class, sql, new Object[] {username});

			String displayType = UserPrefsController.getUserSetting(auth, "displayType");
			if (displayType == null) {
				displayType = Constants.DISPLAY_TYPE_NAME_FIRST;
			}

			contacts = org.claros.intouch.contacts.utility.Utility.sortContacts(contacts, displayType.equals(Constants.DISPLAY_TYPE_NAME_FIRST));
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return contacts;
	}

	/**
	 * @param auth
	 * @param address
	 * @param company
	 * @param email
	 * @param name
	 * @param phone
	 * @return
	 */
	public static List searchContactsByNameEmailNick(String username, String str, boolean onlyWithEmail) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		try {
			dao = Utility.getDbConnection();
			
			String sql = "SELECT * FROM CONTACTS WHERE USERNAME=? ";

			// search emails
			if (str != null && str.trim().length() != 0) {
				str = str.toUpperCase();

				sql += "and (" +
					   "	upper(EMAIL_PRIMARY) like '%" + str + "%' or " +
					   "	upper(EMAIL_ALTERNATE) like '%" + str + "%' or " +
					   "	upper(FIRST_NAME) like '%" + str + "%' or " +
					   "	upper(MIDDLE_NAME) like '%" + str + "%' or " +
					   "	upper(NICK_NAME) like '%" + str + "%' or " +
					   "	upper(LAST_NAME) like '%" + str + "%' " + 
					   "	) ";
			}
			if (onlyWithEmail) {
				sql += "and EMAIL_PRIMARY like '%@%' ";
			}
			contacts = dao.readList(Contact.class, sql, new Object[] {username});
			contacts = org.claros.intouch.contacts.utility.Utility.sortContacts(contacts, true);
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return contacts;
	}


	/**
	 * @param auth
	 * @param address
	 * @param company
	 * @param email
	 * @param name
	 * @param phone
	 * @return
	 */
	public static Contact searchContactByNick(String username, String str) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		Contact contact = null;
		try {
			dao = Utility.getDbConnection();
			String sql = "SELECT * FROM CONTACTS WHERE USERNAME=? AND upper(NICK_NAME) = ? ";
			contacts = dao.readList(Contact.class, sql, new Object[] {username, str.toUpperCase(new Locale("en", "US"))});
			if (contacts.size() == 1) {
				contact = (Contact)contacts.get(0);
			}
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return contact;
	}

	/**
	 * 
	 * @param username
	 * @param email
	 * @return
	 * @throws Exception
	 */
	public static Contact searchContactByEmail(String username, String email) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		Contact contact = null;
		try {
			dao = Utility.getDbConnection();
			String sql = "SELECT * FROM CONTACTS WHERE USERNAME=? AND (" +						 "	upper(EMAIL_PRIMARY) = ? or " +
						 "	upper(EMAIL_ALTERNATE) = ?)";
			email = email.toUpperCase(new Locale("en", "US"));
			contacts = dao.readList(Contact.class, sql, new Object[] {username, email, email});
			if (contacts.size() == 1) {
				contact = (Contact)contacts.get(0);
			}
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		return contact;
	}
	
	/**
	 * 
	 * @param username
	 * @param emailAddress
	 * @return
	 * @throws Exception
	 */
	public static boolean searchContactExistsByEmail(String username, String emailAddress) throws Exception {
		IGenericDao dao = null;
		List contacts = null;
		try {
			dao = Utility.getDbConnection();
			String sql = "SELECT * FROM CONTACTS WHERE USERNAME=? AND (" +
						 "	lower(EMAIL_PRIMARY) = ? or " +
						 "	lower(EMAIL_ALTERNATE) = ?)";
			String tmpEmail = emailAddress.toLowerCase(new Locale("en", "US"));
			contacts = dao.readList(Contact.class, sql, new Object[] {username, tmpEmail, tmpEmail});
		} finally {
			JdbcUtil.close(dao);
			dao = null;
		}
		
		if (contacts == null || contacts.size() == 0) {
			return false;
		} else {
			return true;
		}
	}
	
	/**
	 * 
	 * @param auth
	 * @param adr
	 * @throws Exception
	 */
	public static void saveSenderFromAddr(AuthProfile auth, InternetAddress adr) throws Exception {
		
		String fullName = org.claros.commons.utility.Utility.doCharsetCorrections(adr.getPersonal());
		String emailAddress = org.claros.commons.utility.Utility.doCharsetCorrections(adr.getAddress());

		// if this e-mail previously exists omit it. so let's search for it first.
		if (!searchContactExistsByEmail(auth.getUsername(), emailAddress)) {
			// save it.
			if (fullName != null) {
				fullName = fullName.trim();
			}

			int firstPos = fullName.indexOf(" ");
			String firstName = fullName;
			if (firstPos > 0) {
				firstName = fullName.substring(0, firstPos).trim();
			}
			
			int lastPos = fullName.lastIndexOf(" ");
			String lastName = "";
			if (lastPos > 0) {
				lastName = fullName.substring(lastPos).trim();
			}
			String middleName = "";
			if (firstPos > 0 && lastPos > 0 && firstPos != lastPos) {
				middleName = fullName.substring(firstPos, lastPos).trim();
			}
			if (firstName == null || firstName.equals("")) {
				firstName = emailAddress.substring(0, emailAddress.indexOf("@"));
			}
			
			Contact contact = new Contact();
			contact.setFirstName(firstName);
			contact.setMiddleName(middleName);
			contact.setLastName(lastName);
			contact.setEmailPrimary(emailAddress);
			contact.setUsername(auth.getUsername());
			ContactsController.saveContact(auth, contact);
		}
	}
}
